﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ITAP.ShprossesBuilder.Modelling.Components.Constraints;
using System.Drawing;
using ITAP.Core.Modelling.Primitives;
using ITAP.Core.Modelling;

namespace ITAP.ShprossesBuilder.Modelling.Components
{
    [Serializable]
    public class ShprossChain : IEndedComponent
    {
        public ShprossChain()
        {
            this.connectedComponents = new List<IComponent>();
            this.innerComponents = new List<IComponent>();
            this.constraints = new List<IConstraint>();
            this.primitives = new List<IPrimitive>();
            this.componentsInTolerance = new List<IComponent>();
            this.acceptedComponentTypesToConnect = new ConnectionInfo();
        }

        #region IComponent Members
        private int serialNumber;
        public int SerialNumber
        {
            get
            {
                return serialNumber;
            }
            set
            {
                serialNumber = value;
            }
        }
        private List<IConstraint> constraints;
        public List<IConstraint> Constraints
        {
            get { return constraints; }
        }

        private List<IComponent> connectedComponents;
        public List<IComponent> ConnectedComponents
        {
            get { return connectedComponents; }
        }

        private List<IComponent> innerComponents;
        public List<IComponent> InnerComponents
        {
            get { return innerComponents; }
        }

        public List<IComponent> AllInnerComponents
        {
            get { return innerComponents; }
        }

        public double Tolerance
        {
            get
            {
                return 0;
            }
            set
            {
            }
        }

        public RectangleF BoundingBox
        {
            get
            {
                throw new NotImplementedException();
            }
        }

        public bool IsUpdateRequired
        {
            get
            {
                return false;
            }
            set
            {
            }
        }

        private List<IPrimitive> primitives;

        public List<IPrimitive> Primitives
        {
            get { return primitives; }
        }

        public IComponent ConnectTo(IComponent component)
        {
            if (this.connectedComponents.Contains(component))
                return null;

            this.connectedComponents.Add(component);
            return this;
        }

        public IComponent DisconnectFrom(IComponent component)
        {
            if (this.connectedComponents.Contains(component))
            {
                Shpross shpross = component as Shpross;
                shpross.Chain = null;
                this.connectedComponents.Remove(component);
                return this;
            }
            else
                return null;
        }

        public bool CanConnect(IComponent component)
        {
            throw new NotImplementedException();
        }

        public void Update()
        {
            foreach (IConstraint constraint in this.constraints)
            {
                bool isChecked = false;
                try
                {
                    isChecked = constraint.Check(this);
                }
                catch (Exception ex)
                {
                    FatalErrorEventArgs e = new FatalErrorEventArgs();
                    e.FatalConstraint = constraint;
                    e.FatalException = ex;
                    this.FatalModelError.Invoke(this, e);
                    continue;
                }

                if (!isChecked)
                {
                    ComponentConstraintEventArgs e = new ComponentConstraintEventArgs(constraint);
                    this.BeforeFixingConstraint.Invoke(this, e);
                    if (!e.CancelFixing)
                        constraint.Fix(this);
                    this.AfterFixingConstraint.Invoke(this, e);
                }
            }
        }

        public void AcceptVisitor(IModelVisitor visitor)
        {
            visitor.Visit(this);
            //    throw new NotImplementedException();
        }

        public bool IsInTolerance(ModelPoint point)
        {
            throw new NotImplementedException();
        }

        public bool IsInTolerance(ModelPoint point, double tolerance)
        {
            return false;
        }

        public List<IComponent> GetComponentsByPoint(ModelPoint point, double tolerance)
        {
            throw new NotImplementedException();
        }

        public bool MoveTo(ModelPoint destination)
        {
            return true;
        }

        public bool MoveTo(ModelPoint destination, RectangleF boundingRectangle)
        {
            return true;
        }

        public bool MoveWithOffset(ModelVector offset)
        {
            return true;
        }

        public bool MoveWithOffset(ModelVector offset, RectangleF boundingRectangle)
        {
            return true;
        }

        public bool Rotate(double angleOffset, ModelPoint rotateCenter)
        {
            return true;
        }

        public bool Rotate(double angleOffset, ModelPoint rotateCenter, RectangleF boundingRectangle)
        {
            throw new NotImplementedException();
        }

        public void Rotate(double angleOffset)
        {
            throw new NotImplementedException();
        }

        public bool Rotate(double angleOffset, RectangleF boundingRectangle)
        {
            throw new NotImplementedException();
        }

        public ModelPoint Position
        {
            get
            {
                return (ModelPoint)this.connectedComponents[0].Position.Clone();
            }
        }

        public EndType GetComponentNearestEndType(IComponent component)
        {
            throw new NotImplementedException();
        }

        public List<Type> PreUpdatePriority
        {
            get { throw new NotImplementedException(); }
        }

        public List<Type> PostUpdatePriority
        {
            get { throw new NotImplementedException(); }
        }

        private IComponent parent;
        public IComponent Parent
        {
            get
            {
                return parent;
            }
            set
            {
                parent = value;
            }
        }

        //public bool CheckConstraints()
        //{
        //    throw new NotImplementedException();
        //}

        //public bool CheckCriticalConstraints()
        //{
        //    throw new NotImplementedException();
        //}

        //public bool CheckAllConstraints()
        //{
        //    throw new NotImplementedException();
        //}

        //public bool CheckAllCriticalConstraints()
        //{
        //    throw new NotImplementedException();
        //}

        public bool EnableConstraintsFixing
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        public bool EnableAllConstraintsFixing
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        public List<Type> CriticalConstraintTypes
        {
            get { throw new NotImplementedException(); }
        }

        private ConnectionInfo acceptedComponentTypesToConnect;

        public ConnectionInfo AcceptedComponentTypesToConnect
        {
            get { return acceptedComponentTypesToConnect; }
        }

        private string article;
        public string Article
        {
            get
            {
                return article;
            }
            set
            {
                article = value;
            }
        }

        private string name;
        public string Name
        {
            get
            {
                return name;
            }
            set
            {
                name = value;
            }
        }

        public IComponent ConnectToEnded(IEndedComponent endedComponent, EndType endToConnect)
        {
            return this.ConnectTo(endedComponent);
            //  throw new NotImplementedException();
        }

        public event ComponentConstraintEventDelegate BeforeFixingConstraint;

        public event ComponentConstraintEventDelegate AfterFixingConstraint;

        public event FatalModelErrorDelegate FatalModelError;

        public bool IsConnected(IComponent other)
        {
            throw new NotImplementedException();
        }

        public void AddInnerComponent(IComponent component)
        {
            throw new NotImplementedException();
        }

        public bool RemoveInnerComponent(IComponent component)
        {
            throw new NotImplementedException();
        }

        //public void RemoveAllInnerComponents()
        //{
        //    this.RemoveAllInnerComponentsFromComponent();
        //}

        public void BeforeFixingInnerComponentConstraintEvent(IComponent sender, ITAP.ShprossesBuilder.Modelling.Components.Constraints.ComponentConstraintEventArgs e)
        {
            if (this.BeforeFixingConstraint != null)
            {
                this.BeforeFixingConstraint.Invoke(sender, e);
            }

        }

        public void AfterFixingInnerComponentConstraintEvent(IComponent sender, ITAP.ShprossesBuilder.Modelling.Components.Constraints.ComponentConstraintEventArgs e)
        {
            if (this.AfterFixingConstraint != null)
            {
                this.AfterFixingConstraint.Invoke(sender, e);
            }
        }

        public void FatalModelErrorEvent(IComponent sender, FatalErrorEventArgs e)
        {
            if (this.FatalModelError != null)
                this.FatalModelError.Invoke(sender, e);
        }

        public ModelPoint GetNearestPointOnComponent(ModelPoint point, StickConnectionType stickType, out StickConnectionType sticked, ProjectionType projectionType)
        {
            throw new NotImplementedException();
        }

        public ModelPoint GetNearestPointOnComponent(ModelPoint point, StickConnectionType stickType, out StickConnectionType sticked, out IComponent innerComponent, ProjectionType projectionType)
        {
            throw new NotImplementedException();
        }

        public ModelPoint GetNearestPointOnComponent(ModelPoint point, ModelPoint measurePoint, StickConnectionType stickType, out StickConnectionType sticked, ProjectionType projectionType)
        {
            throw new NotImplementedException();
        }

        public ModelPoint GetNearestPointOnComponent(ModelPoint point, ModelPoint measurePoint, StickConnectionType stickType, out StickConnectionType sticked, out IComponent innerComponent, ProjectionType projectionType)
        {
            throw new NotImplementedException();
        }

        public bool Selected
        {
            get
            {
                return false;
            }
            set
            {
                //throw new NotImplementedException();
            }
        }

        public bool SelectByPoint(ModelPoint point)
        {
            throw new NotImplementedException();
        }

        public bool IsPointInComponent(ModelPoint point)
        {
            throw new NotImplementedException();
        }
        private List<IComponent> componentsInTolerance;
        public List<IComponent> ComponentsInTolerance
        {
            get { return componentsInTolerance; }
        }

        public bool AutoConnectComponentsInTolerance
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        public void DisconnectComponentsInTolerance()
        {
            throw new NotImplementedException();
        }

        //public void DisconnectFromAll()
        //{
        //    this.DisconnectFromAllConnectedComponents();

        //    //List<IComponent> componentsToDisconnect = new List<IComponent>();
        //    //foreach (IComponent connectedComponent in this.ConnectedComponents)
        //    //{
        //    //    componentsToDisconnect.Add(connectedComponent);
        //    //}
        //    //foreach (IComponent connectedComponent in componentsToDisconnect)
        //    //{
        //    //    ConnectionProvider.Disconnect(this, connectedComponent);
        //    //}

        //}

        public void MoveToZeroPoint()
        {
            throw new NotImplementedException();
        }

        public void MoveToZeroXPoint()
        {
            throw new NotImplementedException();
        }

        public void MoveToZeroYPoint()
        {
            throw new NotImplementedException();
        }

        public bool InaccessibleFromMaterials
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        public int UniqueId
        {
            get { return -1; }
        }

        public List<int> AcceptedUniqueIdsToConnect
        {
            get { throw new NotImplementedException(); }
        }

        public bool UniqueIdsEnabled
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        #endregion

        #region IModelVisitor Members

        public void Visit(Model model)
        {
        }

        public void Visit(Connector connector)
        {
        }

        public void Visit(Shpross shpross)
        {
        }

        public void Visit(Spacer spacer)
        {
        }

        public void Visit(ShprossConnectorStub stub)
        {
        }

        public void Visit(ShprossConnector shprossConnector)
        {
        }

        public void Visit(SpacerElement spacerElement)
        {
        }

        public void Visit(SpacerConnector spacerConnector)
        {
        }

        public void Visit(ModelCell modelCell)
        {
        }

        public void Visit(ModelContainer modelContainer)
        {
        }

        public void Visit(StickConnector stickConnector)
        {
        }

        public void Visit(SnapOnCap snapOnCap)
        {
        }

        public void Visit(ShprossEndToEndConnector endToEndConnector)
        {
        }

        #endregion

        #region ICloneable Members

        public object Clone()
        {
            throw new NotImplementedException();
        }

        #endregion

        #region IEndedComponent Members

        //public bool EnableAutoCuts
        //{
        //    get
        //    {
        //        throw new NotImplementedException();
        //    }
        //    set
        //    {
        //        throw new NotImplementedException();
        //    }
        //}

        public ModelPoint StartPoint
        {
            get
            {
                Shpross startShpross = this.connectedComponents[0] as Shpross;
                if (startShpross.EndConnectedComponent is ShprossEndToEndConnector)
                    return startShpross.StartPoint.Clone() as ModelPoint;
                else
                    return startShpross.EndPoint.Clone() as ModelPoint;
            }
            set
            {
            }
        }

        public ModelPoint EndPoint
        {
            get
            {
                Shpross endShpross = this.connectedComponents[this.connectedComponents.Count - 1] as Shpross;
                if (endShpross.EndConnectedComponent is ShprossEndToEndConnector)
                    return endShpross.StartPoint.Clone() as ModelPoint;
                else
                    return endShpross.EndPoint.Clone() as ModelPoint;
            }
            set
            {
            }
        }

        public Angle StartCutAngle
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        public Angle EndCutAngle
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        public double Width
        {
            get
            {
                return (this.connectedComponents[0] as Shpross).Width;
            }
            set
            {
                throw new NotImplementedException();
            }
        }

   
        public double LengthWithSpacerIndents
        {
            get
            {
                double length = 0;
                foreach (Shpross shpross in this.connectedComponents)
                {
                    length += shpross.LengthWithSpacerIndents;
                }
                return length;
            }
        }

        public double Length
        {         
            get
            {
                double length = 0;
                foreach (Shpross shpross in this.connectedComponents)
                {
                    length += shpross.Length;
                }
                return length;
            }
            set
            {
            }
        }

        public IComponent StartConnectedComponent
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        public IComponent EndConnectedComponent
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        public IComponent ConnectTo(IComponent component, EndType endForConnect)
        {
            throw new NotImplementedException();
        }

        public List<Type> ConnectPriorityForEnds
        {
            get { throw new NotImplementedException(); }
        }

        public void MoveStartPointTo(ModelPoint destination)
        {
        }


        public void MoveEndPointTo(ModelPoint destination)
        {
        }


        public void SetHeight(double height, RectangleF boundingRectangle)
        {
        }

        public double Height
        {
            get
            {
                return double.NaN;
            }
            set
            {
            }
        }

        //public EndType IsConnectedToEnd(IComponent component)
        //{

        //    return this.GetConnectedEndType(component);
        //}

        #endregion

        #region IModelVisitor Members


        public void Visit(ShprossChain shprossChain)
        {
            //   throw new NotImplementedException();
        }

        #endregion

        #region IComponent Members


        public IComponent Copy()
        {
            throw new NotImplementedException();
        }

        #endregion

        #region IModelVisitor Members


        public void Visit(SpacerContainer spacerContainer)
        {
           // throw new NotImplementedException();
        }

        #endregion

        #region IModelVisitor Members


        public void Visit(CrossConnector crossConnector)
        {
      //      throw new NotImplementedException();
        }

        #endregion

        #region IEndedComponent Members


        public void MoveStartPointTo(ModelPoint destination, RectangleF boundingRectangle, bool allowOutOfRectangleForOneEnd)
        {
            
        }

        public void MoveEndPointTo(ModelPoint destination, RectangleF boundingRectangle, bool allowOutOfRectangleForOneEnd)
        {
          
        }

        #endregion
    }
}
